/* See COPYRIGHT for copyright information. */

#include <inc/mmu.h>
#include <inc/memlayout.h>
#include <inc/trap.h>

#include <kern/picirq.h>


###################################################################
# exceptions/interrupts
###################################################################

/* TRAPHANDLER defines a globally-visible function for handling a trap.
 * It pushes a trap number onto the stack, then jumps to _alltraps.
 * Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
 *
 * You shouldn't call a TRAPHANDLER function from C, but you may
 * need to _declare_ one in C (for instance, to get a function pointer
 * during IDT setup).  You can declare the function with
 *   void NAME();
 * where NAME is the argument passed to TRAPHANDLER.
 */
#define TRAPHANDLER(name, num)						\
	.globl name;		/* define global symbol for 'name' */	\
	.type name, @function;	/* symbol type is function */		\
	.align 2;		/* align function definition */		\
	name:			/* function starts here */		\
	pushl $(num);							\
	jmp _alltraps

/* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
 * It pushes a 0 in place of the error code, so the trap frame has the same
 * format in either case.
 */
#define TRAPHANDLER_NOEC(name, num)					\
	.globl name;							\
	.type name, @function;						\
	.align 2;							\
	name:								\
	pushl $0;							\
	pushl $(num);							\
	jmp _alltraps


/*
 * Lab 3: Your code here for generating entry points for the different traps.
 */


/*
 * Lab3 challenge, 其实如果熟悉汇编, 以及GNU assembler的话不难写出
 * 下面大部分参照这里: 
 * https://github.com/Clann24/jos/blob/master/lab3/code/kern/trapentry.S
 */
#define ec(name, num)   \
.data;\
    .long name;\
.text;\
    .globl name;\
    .type name, @function;\
    .align 2;\
    name:\
    pushl $(num);\
    jmp _alltraps

#define noec(name, num) \
.data;\
    .long name;\
.text;\
    .globl name;\
    .type name, @function;\
    .align 2;\
    name:\
    pushl $0;\
    pushl $(num);\
    jmp _alltraps

#define empty_handler()\
.data;\
    .long default_trap_handler;

#define empty_irq_handler()\
.data;\
    .long irq_error_handler;

/*
 * 解释一下上面的代码, 省得查手册
 * .data 这个directive作用是把之后的部分都汇编到数据段
 * .text 这个是把之后的部分都汇编到程序段
 * 虽然这两个先后写在一起, 但是as汇编器会把它们放到不同的段中
 *
 * .align <n> 表示按照n对齐, 即接下来的部分一定是在可以被n整除的地址处
 */

.text
// 默认处理
TRAPHANDLER_NOEC(default_trap_handler, T_DEFAULT)

TRAPHANDLER_NOEC(irq_error_handler, IRQ_ERROR)


.data
    .p2align 2  // 按照2^2对齐, 即4
    .globl funcs
funcs:

.text
    noec(vector0, T_DIVIDE)		
    noec(vector1, T_DEBUG)		
    noec(vector2, T_NMI)		
    noec(vector3, T_BRKPT)		
    noec(vector4, T_OFLOW)		
    noec(vector5, T_BOUND)		
    noec(vector6, T_ILLOP)		
    noec(vector7, T_DEVICE)		
    noec(vector8, T_DBLFLT)		
    empty_handler()
    noec(vector10, T_TSS)		
    noec(vector11, T_SEGNP)		
    noec(vector12, T_STACK)		
    ec(vector13, T_GPFLT)		
    ec(vector14, T_PGFLT)		
    empty_handler()
    noec(vector16, T_FPERR)		
    noec(vector17, T_ALIGN)		
    noec(vector18, T_MCHK)		
    noec(vector19, T_SIMDERR)		
.data
    .space 12*4
.text
    noec(irq0, IRQ_OFFSET + IRQ_TIMER)
    noec(irq1, IRQ_OFFSET + IRQ_KBD)
    empty_irq_handler()
    empty_irq_handler()
    noec(irq4, IRQ_OFFSET + IRQ_SERIAL)
    empty_irq_handler()
    empty_irq_handler()
    noec(irq7, IRQ_OFFSET + IRQ_SPURIOUS)
    empty_irq_handler()
    empty_irq_handler()
    empty_irq_handler()
    empty_irq_handler()
    empty_irq_handler()
    empty_irq_handler()
    noec(irq14, IRQ_OFFSET + IRQ_IDE)
    empty_irq_handler()
.text
    noec(vector48, T_SYSCALL)		



/*
 * Lab 3: Your code here for _alltraps
 */

// like alltraps in xv6
_alltraps:
    pushl %ds
    pushl %es
    pushal


    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es

    // call into trap
    pushl %esp
    call trap

    // 不需要像xv6那样pop了，在trap里面会有pop frame的
